﻿using System.Collections.Generic;
using System.Linq;
using JetBrains.ReSharper.Daemon.CSharp.Stages;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Stages.Dispatcher;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.Util.Special;
using MugenMvvmToolkit.ReSharper.Highlighting;
using MugenMvvmToolkit.ReSharper.Infrastructure;

namespace MugenMvvmToolkit.ReSharper.ViewModels.Analyzers
{
    [ElementProblemAnalyzer(new[] { typeof(IPropertyDeclaration) },
        HighlightingTypes = new[] { typeof(ResolvedLiteralHighlighting), typeof(InvalidModelPropertyAttributeHighlighting), typeof(UnusedModelPropertyAttributeHighlighting) })]
    public class ModelPropertyAttributeAnalyzer : ElementProblemAnalyzerBase<IPropertyDeclaration>
    {
        #region Overrides of ElementProblemAnalyzerBase<IAttribute>

        protected override void Run(IPropertyDeclaration element, ElementProblemAnalyzerData data, IHighlightingConsumer consumer)
        {
            foreach (var attribute in element.Attributes)
            {
                Validate(attribute, element, consumer);
            }
        }

        #endregion

        #region Methods

        private void Validate(IAttribute element, IPropertyDeclaration propertyDeclaration, IHighlightingConsumer consumer)
        {
            var literalExpression = ToolkitExtensions.TryGetModelPropertyAttributeValue(element, TypeProvider);
            if (literalExpression == null)
                return;
            var modelClass = ToolkitExtensions
                .GetEntityModelType(element.FindParent<IClassLikeDeclaration>())
                .IfNotNull(type => type.GetClassType());
            if (modelClass == null)
                return;
            var properties = new HashSet<string>(ToolkitExtensions.GetModelProperties(modelClass).Select(property => property.ShortName));

            var s = literalExpression.ConstantValue.Value as string;
            if (s == null || !properties.Contains(s))
                consumer.AddHighlighting(new InvalidModelPropertyAttributeHighlighting(modelClass, literalExpression));
            else if (propertyDeclaration.DeclaredName == s)
                consumer.AddHighlighting(new UnusedModelPropertyAttributeHighlighting(propertyDeclaration, element));
            else
                consumer.AddHighlighting(new ResolvedLiteralHighlighting(literalExpression));
        }

        #endregion
    }
}